home *** CD-ROM | disk | FTP | other *** search
/ SPACE 2 / SPACE - Library 2 - Volume 1.iso / apps / 223 / emacssrc / files.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-17  |  24.1 KB  |  1,118 lines

  1. /*
  2.  * file file.c:
  3.  *
  4.  * The routines in this file
  5.  * handle the reading and writing of
  6.  * disk files. All of details about the
  7.  * reading and writing of the disk are
  8.  * in "fileio.c".
  9.  */
  10. #include    <stdio.h>
  11. #include    "ed.h"
  12.  
  13. #if AtST
  14. /* overlay "me2"        dal: not available in Alcyon C */
  15. #endif
  16.  
  17. /*
  18.  * Read a file into the current
  19.  * buffer. This is really easy; all you do it
  20.  * find the name of the file, and call the standard
  21.  * "read a file into the current buffer" code.
  22.  * Bound to "C-X C-R".   mb: added keep&insert stuff.
  23.  */
  24. fileread(f, n)
  25.     {
  26.     register BUFFER    *bp;
  27.     register int    s, ins;
  28.     char    fname[NFILEN];
  29.  
  30.     bp = curbp;
  31.     if (lforw(bp->b_linep) != bp->b_linep)     /* buf not empty */
  32.         {
  33.         ins = mlyesno("Keep current text");
  34.         if (ins == ABORT) 
  35.             {
  36.             mlwrite("[aborted]");
  37.             return (ABORT);
  38.             }
  39.         if (ins != TRUE) 
  40.             {
  41.             if ((s=bclear(bp)) != TRUE)
  42.                 return (s);
  43.             }
  44.         }
  45.     else
  46.         ins = FALSE;
  47.     if ((s=mlgetfn("File to read", fname, NFILEN)) != TRUE)
  48.         return (s);
  49.     if ((s=readin(fname)) != FIOEOF)
  50.         return (FALSE);
  51.     bp->b_flag &= ~BFTEMP;
  52.     if (ins)
  53.         bp->b_flag |= BFCHG;
  54.     else 
  55.         {
  56.         fullpath(bp->b_fname, fname);    /* dal: normalize */
  57.         bp->b_flag &= ~BFCHG;
  58.         }
  59.     bp->b_flag |= BFEDIT;            /* read for editing */
  60.     return (TRUE);  
  61.     }
  62.  
  63. /*
  64.  * Select a file for editing.
  65.  * Look around to see if you can find the
  66.  * fine in another buffer; if you can find it
  67.  * just switch to the buffer. If you cannot find
  68.  * the file, create a new buffer, read in the
  69.  * text, and switch to the new buffer.
  70.  * Bound to C-X C-V.
  71.  * mb: combined "out" portion of new & old cases.
  72.  */
  73. filevisit(f, n)
  74.     {
  75.     register BUFFER *bp;
  76.     register WINDOW *wp;
  77.     register LINE   *lp;
  78.     register int    i;
  79.     register int    s;
  80.     char        bname[NBUFN];
  81.     char        fname[NFILEN];
  82.     char        *msg;
  83.     int        old = FALSE;
  84.  
  85.     if ((s=mlgetfn("File to visit", fname, NFILEN)) != TRUE)
  86.         return (s);
  87.     fullpath(fname, fname);            /* dal: added */
  88.     for (bp=bheadp; bp!=NULL; bp=bp->b_bufp) 
  89.         {
  90.         if ((bp->b_flag&BFTEMP)==0 && strcmp(bp->b_fname, fname)==0) 
  91.             {
  92.             old = TRUE;
  93.             break;
  94.             }
  95.         }
  96.     if (old) goto out;
  97.  
  98.     makename(bname, fname);            /* New buffer name.     */
  99.     while ((bp=bfind(bname, FALSE, 0)) != NULL) 
  100.         {
  101.         s = mlgets("Buffer name", "default: existing buffer!",
  102.             bname, NBUFN, CRLF);
  103.         if (s == ABORT)            /* ^G to just quit      */
  104.             return (ABORT);
  105.         if (bname[0] == '\0')         /* CR to clobber it     */
  106.             {
  107.             if (bclear(bp) != TRUE)
  108.                 return (FALSE);
  109.             makename(bname, fname);
  110.             break;
  111.             }
  112.         }
  113.     if (bp==NULL && (bp=bfind(bname, TRUE, 0))==NULL) 
  114.         {
  115.         mlwrite("Cannot create buffer");
  116.         return (FALSE);
  117.         }
  118.  
  119. out:
  120.     gotobuf(bp);            /* mb: in buffer.c */
  121.     curwp->w_linep = bp->b_linep;
  122.     curwp->w_flag |= WFMODE|WFFORCE|WFHARD;
  123.     if (old)
  124.         mlwrite("[Old buffer]");
  125.     else 
  126.         {
  127.         if ((s=readin(fname)) != FIOEOF) 
  128.             {
  129.             gotobuf(oldbp);        /* back where we started */
  130.             freebuf(oldbp);        /* now oldbp = abandoned */
  131.             return (FALSE);        /* (empty) visited buf   */
  132.             }
  133.         fullpath(bp->b_fname, fname);    /* dal: normalize */
  134.         bp->b_flag &= ~(BFTEMP|BFCHG);
  135.         }
  136.     bp->b_flag &= ~BFEDIT;              /* visit for viewing */
  137.     return (TRUE);
  138.     }
  139.  
  140. /*
  141.  * Read file "fname" into the current buffer.
  142.  * Called by both the read and visit commands.
  143.  * Return the final status of the read.
  144.  * Also called by the mainline, to read in a file
  145.  * specified on the command line as an argument.
  146.  */
  147. readin(fname)
  148. char    fname[];
  149.     {
  150.     register LINE   *lp1;
  151.     register char    *cp;
  152.     register int    i;
  153.     register int    nbytes;
  154.     register int    nline;
  155.     register int    s;
  156.     WINDOW        *wp;
  157.     BUFFER        *bp;
  158.     LINE        *lp2;
  159.     LINE        *flp;
  160.     char        line[NLINE];
  161.     int        longline = FALSE;
  162.  
  163.     s = ffropen(fname);
  164.     if (s == FIOERR)
  165.         mlwrite("Error opening file");
  166.     if (s == FIOFNF)
  167.         mlwrite("File not found");
  168.     if (s != FIOSUC)
  169.         return (s);
  170.     mlwrite("[Reading file...]");
  171.     bp = curbp;
  172.     flp = lforw(bp->b_linep);
  173.     nline = 0;
  174.     while (((s=ffgetline(line, NLINE)) == FIOSUC ) || (s==FIOFNF)) 
  175.         {
  176.         /* dal: FNF indicates no nl at eof. save last line and exit. */
  177.  
  178.         nbytes = strlen(line);
  179.         if (nbytes == NLINE-1)        /* "long line"    */
  180.             longline = TRUE;    /* Keep message */
  181.         if ((lp1=lnalloc(nbytes)) == NULL) 
  182.             {
  183.             s = FIOERR;        /* Keep message on the  */
  184.             break;            /* display.        */
  185.             }
  186.  
  187. /* mb: original version:
  188.  
  189.         lp2 = lback(curbp->b_linep);
  190.         lp2->l_fp = lp1;
  191.         lp1->l_fp = curbp->b_linep;
  192.         lp1->l_bp = lp2;
  193.         curbp->b_linep->l_bp = lp1;
  194.         for (i=0; i<nbytes; i++)
  195.             lputc(lp1, i, line[i]);
  196.  
  197. - instead, enable insertion into existing text: */
  198.  
  199.         if (nline == 0)
  200.             flp = lp1;
  201.         lp2 = lback(curwp->w_dotp);
  202.         lp2->l_fp = lp1;
  203.         lp1->l_fp = curwp->w_dotp;
  204.         lp1->l_bp = lp2;
  205.         curwp->w_dotp->l_bp = lp1;
  206.         cp = line;
  207.         for (i=0; i<nbytes; i++)
  208.             lputc(lp1, i, *cp++);
  209.  
  210.         nline++;
  211.         }
  212.     frclose();                /* Ignore errors.       */
  213.     if (s==FIOEOF && (! longline))        /* Don't zap message!   */
  214.         mlwrite("[Read %d line(s)]", nline);
  215.     for (wp=wheadp; wp!=NULL; wp=wp->w_wndp) 
  216.         {
  217.         if (wp->w_bufp == curbp) 
  218.             {
  219. /* original:        wp->w_linep = lforw(curbp->b_linep);
  220.             wp->w_dotp  = lforw(curbp->b_linep);
  221.             wp->w_doto  = 0;
  222.  
  223.   - mb: */        wp->w_linep = flp;
  224.             wp->w_dotp  = flp;
  225.             wp->w_doto  = 0;
  226.             wp->w_force = 0;
  227.             wp->w_flag |= WFMODE|WFHARD|WFFORCE;
  228.             wp->w_markp = NULL;
  229.             wp->w_marko = 0;
  230.             }
  231.         }
  232.     /* dal: FNF indicates no nl at eof. fix return code and then exit. */
  233.     if(s == FIOFNF)
  234.         s = FIOEOF;
  235.  
  236.     return (s);
  237.     }
  238.  
  239. /*
  240.  * Take a file name, and from it
  241.  * fabricate a buffer name. This routine knows
  242.  * about the syntax of file names on the target system.
  243.  * I suppose that this information could be put in
  244.  * a better place than a line of code.
  245.  */
  246. makename(bname, fname)
  247. char    bname[];
  248. char    fname[];
  249.     {
  250.     register char   *cp1;
  251.     register char   *cp2;
  252.     register char    c;
  253.  
  254. #if    !AtST
  255.     /* NOTE: be sure that your implementation of strrchr() will
  256.          correctly locate the terminating '\0' as needed here.    */
  257.     cp1 = strrchr(fname, '\0');
  258. #endif
  259. #if     VMS
  260.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!=']')
  261.         --cp1;
  262. #endif
  263. #if     CPM
  264.     while (cp1!=&fname[0] && cp1[-1]!=':')
  265.         --cp1;
  266. #endif
  267. #if     MSDOS
  268.     while (cp1!=&fname[0] && cp1[-1]!=':' && cp1[-1]!='\\')
  269.         --cp1;
  270. #endif
  271. #if     AtST
  272.     if((cp1 = strrpbrk(fname, ":\\")) == NULL)
  273.         cp1 = fname;
  274.     else
  275.         ++cp1;
  276. #endif
  277. #if     V7
  278.     while (cp1!=&fname[0] && cp1[-1]!='/')
  279.         --cp1;
  280. #endif
  281.     strcpy(bname, cp1);            /* copy tail of file name */
  282.     strlwr(bname);                /* lowercase the string */
  283.     }
  284.  
  285. /*
  286.  * Ask for a file name, and write the
  287.  * contents of the current buffer to that file.
  288.  * Update the remembered file name and clear the
  289.  * buffer changed flag. This handling of file names
  290.  * is different from the earlier versions, and
  291.  * is more compatible with Gosling EMACS than
  292.  * with ITS EMACS. Bound to "C-X C-W".
  293.  * mb: added default filename.
  294.  */
  295. filewrite(f, n)
  296.     {
  297.     register char   *cp1;
  298.     register int    c;
  299.     int    s;
  300.     char    fname[NFILEN];
  301.     WINDOW     *wp;
  302.  
  303.     cp1 = curbp->b_fname;
  304.     if(*cp1 == '\0')
  305.         cp1 = NULL;
  306.  
  307.     if ((s=mlgets("File to write", cp1, fname, NFILEN, CRLF)) == ABORT)
  308.         return (s);
  309.     if (fname[0] == '\0')
  310.         fullpath(fname, curbp->b_fname);
  311.  
  312.     if ((s=writeout(fname)) == TRUE) 
  313.         {
  314.         fullpath(curbp->b_fname, fname);
  315.         curbp->b_flag &= ~BFCHG;
  316.         wp = wheadp;        /* Update mode lines. */
  317.         while (wp != NULL) 
  318.             {
  319.             if (wp->w_bufp == curbp)
  320.                 wp->w_flag |= WFMODE;
  321.             wp = wp->w_wndp;
  322.             }
  323.         }
  324.     return (s);
  325.     }
  326.  
  327. /*
  328.  * Save the contents of the current
  329.  * buffer in its associatd file. Do nothing
  330.  * if nothing has changed (this may be a bug, not a
  331.  * feature). Error if there is no remembered file
  332.  * name for the buffer. Bound to "C-X C-S". May
  333.  * get called by "C-Z".
  334.  */
  335. filesave(f, n)
  336.     {
  337.     register WINDOW *wp;
  338.     register int    s;
  339.  
  340.     if ((curbp->b_flag&BFCHG) == 0)        /* Return, no changes.  */
  341.         return (TRUE);
  342.     if (curbp->b_fname[0] == 0)         /* Must have a name.    */
  343.         {
  344.         mlwrite("No file name");
  345.         return (FALSE);
  346.         }
  347.     if ((s=writeout(curbp->b_fname)) == TRUE) 
  348.         {
  349.         curbp->b_flag &= ~BFCHG;
  350.         wp = wheadp;            /* Update mode lines.   */
  351.         while (wp != NULL) 
  352.             {
  353.             if (wp->w_bufp == curbp)
  354.                 wp->w_flag |= WFMODE;
  355.             wp = wp->w_wndp;
  356.             }
  357.         }
  358.     return (s);
  359.     }
  360.  
  361. /*
  362.  * This function performs the details of file
  363.  * writing. Uses the file management routines in the
  364.  * "fileio.c" package. The number of lines written is
  365.  * displayed. Sadly, it looks inside a LINE; provide
  366.  * a macro for this. Most of the grief is error
  367.  * checking of some sort.
  368.  */
  369. writeout(fn)
  370.     char    *fn;
  371.     {
  372.     register int    s;
  373.     register LINE   *lp;
  374.     register int    nline;
  375.  
  376.     s = ffwopen(fn);
  377.     if (s != FIOSUC) 
  378.         {
  379.         mlwrite("Cannot open file for writing");
  380.         return (FALSE);
  381.         }
  382.  
  383.     mlwrite("[writing file...]");
  384.     lp = lforw(curbp->b_linep);        /* First line.        */
  385.     nline = 0;                /* Number of lines.    */
  386.     while (lp != curbp->b_linep) 
  387.         {
  388.         if ((s=ffputline(&lp->l_text[0], llength(lp))) != FIOSUC)
  389.             break;
  390.         ++nline;
  391.         lp = lforw(lp);
  392.         }
  393.     if (s == FIOSUC)             /* No write error.      */
  394.         {
  395.         s = fwclose();
  396.         if (s == FIOSUC)         /* No close error.      */
  397.             {
  398.             mlwrite("[Wrote %d line(s)]", nline);
  399.             }
  400.         }
  401.     else                    /* Ignore close error   */
  402.         fwclose();            /* if a write error.    */
  403.     if (s != FIOSUC)            /* Some sort of error.  */
  404.         return (FALSE);
  405.     return (TRUE);
  406.     }
  407.  
  408. /*
  409.  * The command allows the user
  410.  * to modify the file name associated with
  411.  * the current buffer. It is like the "f" command
  412.  * in UNIX "ed". The operation is simple; just zap
  413.  * the name in the BUFFER structure, and mark the windows
  414.  * as needing an update.
  415.  */
  416. filename(f, n)
  417.     {
  418.     register WINDOW *wp;
  419.     register int    s;
  420.     char        fname[NFILEN];
  421.  
  422.     if ((s=mlgetfn("New filename", fname, NFILEN)) != TRUE)
  423.         return (s);
  424.     fullpath(curbp->b_fname, fname);
  425.     curbp->b_flag |= BFCHG;
  426.     wp = wheadp;                /* Update mode lines.   */
  427.     while (wp != NULL) 
  428.         {
  429.         if (wp->w_bufp == curbp)
  430.             wp->w_flag |= WFMODE;
  431.         wp = wp->w_wndp;
  432.         }
  433.     return (TRUE);
  434.     }
  435.  
  436.  
  437. /*
  438.  * file fileio.c:
  439.  *
  440.  * mb: Atari ST stuff & BFILES added.
  441.  *
  442.  * The routines in this file
  443.  * read and write ASCII files from the
  444.  * disk. All of the knowledge about files
  445.  * are here. A better message writing
  446.  * scheme should be used.
  447.  */
  448.  
  449. static    FILE    *ffp;        /* File pointer, all functions. */
  450. #if BFILES
  451. static    char    fbufp[FBLOCK];    /* File text buffer            */
  452. static    char    *fbpos;        /* Current position in file text buffer    */
  453. static    char    *ftail;        /* End of file text buffer        */
  454. #if AtST
  455. static    int    hndl = 0;    /* dal: variable was called "handle"    */
  456. #endif
  457. #endif BFILES
  458.  
  459. /*
  460.  * Open a file for reading.
  461.  */
  462. ffropen(fn)
  463.     char    *fn;
  464.     {
  465. #if BFILES
  466.  
  467. #if AtST
  468.     register int  i;
  469.  
  470.     if ((i = open(fn, O_RDONLY)) < 0)
  471.         return ((i == -33) ? FIOFNF : FIOERR);
  472.     hndl = i;
  473.     fbpos = fbufp;
  474.     ftail = fbufp;            /* nothing read yet */
  475.     return (FIOSUC);
  476. #else
  477.     return (FIOERR);
  478. #endif
  479.  
  480. #else    /* if not BFILES */
  481.  
  482. #if AtST|MSDOS
  483.     if ((ffp=fopen(fn, "rb")) == NULL)  /* we handle crlf ourselves */
  484. #else
  485.     if ((ffp=fopen(fn, "r")) == NULL)
  486. #endif
  487.         return (FIOFNF);
  488.     return (FIOSUC);
  489. #endif BFILES
  490.     }
  491.  
  492. /*
  493.  * Open a file for writing.
  494.  * Return TRUE if all is well, and
  495.  * FALSE on error (cannot create).
  496.  */
  497. ffwopen(fn)
  498.     char    *fn;
  499.     {
  500. #if BFILES
  501. #if AtST
  502.     register int i;
  503.  
  504.     if ((i = creat(fn, 0x00)) < 0)
  505.         return (FIOERR);
  506.     hndl = i;
  507.     fbpos = fbufp;
  508.     ftail = fbufp + FBLOCK;
  509.     return (FIOSUC);
  510. #else
  511.     return (FIOERR);
  512. #endif AtST
  513. #else
  514. #if    VMS
  515.     register int    fd;
  516.  
  517.     if ((fd=creat(fn, 0666, "rfm=var", "rat=cr")) < 0
  518.     || (ffp=fdopen(fd, "w")) == NULL)
  519.         return (FIOERR);
  520. #else
  521.     if ((ffp=fopen(fn, "w")) == NULL)
  522.         return (FIOERR);
  523. #endif    VMS
  524.     return (FIOSUC);
  525. #endif BFILES
  526.     }
  527.  
  528. /*
  529.  * Close an input file.
  530.  */
  531. frclose()
  532.     {
  533. #if BFILES
  534.     close(hndl);
  535. #else
  536.     fclose(ffp);
  537. #endif
  538.     }
  539.  
  540. /*
  541.  * Close an output file.
  542.  * Should look at the status in all systems.
  543.  */
  544. fwclose()
  545.     {
  546. #if BFILES
  547.     register int size;
  548.  
  549.     size = ((int) (fbpos - fbufp));
  550.     if (size > 0)         /* something to write out */
  551.         {
  552.         if (write(hndl, fbufp, size) != size) 
  553.             {
  554.             mlwrite("Write error");
  555.             return (FIOERR);
  556.             }
  557.         }
  558.     if (close(hndl) < 0) 
  559.         {
  560.         mlwrite("Error closing file");
  561.         return(FIOERR);
  562.         }
  563. #else
  564. #if     V7
  565.     if (fclose(ffp) != FALSE) 
  566.         {
  567.         mlwrite("Error closing file");
  568.         return(FIOERR);
  569.         }
  570. #else
  571. #if     AtST
  572.     if (ffp != NULL && fclose(ffp) != FALSE) 
  573.         {
  574.         mlwrite("Error closing file");
  575.         return (FIOERR);
  576.         }
  577. #else
  578.     fclose(ffp);
  579. #endif    AtST
  580. #endif    V7
  581. #endif    BFILES
  582.     return (FIOSUC);
  583.     }
  584.  
  585. #if BFILES
  586. bputc(c)
  587.     register int c;
  588.     {
  589.     if (fbpos >= ftail)     /* ram full, write it out */
  590.         {
  591.         if (write(hndl, fbufp, FBLOCK) != FBLOCK)
  592.             return (EOF);
  593.         fbpos = fbufp;
  594.         }
  595.     *fbpos++ = (char) c;
  596.     return (c);
  597.     }
  598. #endif BFILES
  599.  
  600. /*
  601.  * Write a line to the already
  602.  * opened file. The "buf" points to the
  603.  * buffer, and the "nbuf" is its length, less
  604.  * the free newline. Return the status.
  605.  * Check only at the newline.
  606.  */
  607. ffputline(buf, nbuf)
  608. register char   buf[];
  609. register int    nbuf;
  610.     {
  611.     register int    i, c;
  612.  
  613.     c = 0;                /* in case nbuf==0 */
  614.     for (i=0; i<nbuf; ++i)
  615.         {
  616. #if BFILES
  617.         c = bputc(buf[i]);
  618. #else
  619.         c = putc(buf[i], ffp);
  620. #endif
  621.         if (c == EOF)
  622.             break;
  623.         }
  624. #if BFILES
  625.     if (c != EOF)
  626.         c = bputc('\r');
  627.     if (c != EOF)
  628.         c = bputc('\n');
  629.     if (c==EOF)
  630.         {
  631. #else
  632.     if (c != EOF)
  633.         c = putc('\n', ffp);
  634.     if (c==EOF || ferror(ffp) != FALSE) {
  635. #endif
  636.         mlwrite("Write error");
  637.         return (FIOERR);
  638.         }
  639.     return (FIOSUC);
  640.     }
  641.  
  642. /*
  643.  * Read a line from a file,
  644.  * and store the bytes in the supplied
  645.  * buffer. The "nbuf" is the length of the
  646.  * buffer. Complain about long lines and lines
  647.  * at the end of the file that don't have a
  648.  * newline present. Check for I/O errors
  649.  * too. Return status.
  650.  */
  651. ffgetline(buf, nbuf)
  652. register char   buf[];
  653. register int    nbuf;
  654.     {
  655.     register int    c, i;
  656. #if BFILES
  657.     int    size = 1;
  658. #endif
  659.     i = 0;
  660.     --nbuf;
  661. #if BFILES
  662.     for(;;)
  663.         {
  664.         if (fbpos >= ftail)
  665.             {
  666.             size = read(hndl, fbufp, FBLOCK);
  667.             fbpos = fbufp;
  668.             ftail = fbufp + size;
  669.             if (fbpos >= ftail)
  670.                 {
  671.                 c = EOF;
  672.                 break;
  673.                 }
  674.             }
  675.         c = *fbpos++;
  676.         if (c == '\r')
  677.             continue;    /* go get the '\n' */
  678.         if (c == '\n')
  679.             break;
  680. #else
  681.     while ((c=getc(ffp))!=EOF && c!='\n')
  682.         {
  683.         if (c == '\r')
  684.             {
  685.             if ((c=getc(ffp)) != '\n')
  686.                 {
  687.                 ungetc(c, ffp);
  688.                 c = '\n';    /* this should work */
  689.                 }        /*  on all systems! */
  690.             }
  691. #endif BFILES
  692.         buf[i++] = c;
  693.         if (i >= nbuf)
  694.             {
  695.             mlwrite("File has long line: splitted");
  696.             break;
  697.             }
  698.         }
  699.     buf[i] = 0;
  700.     if (c == EOF)
  701.         {
  702. #if BFILES
  703.         if (size != 0)
  704.             {
  705. #else
  706.         if (ferror(ffp) != FALSE)
  707.             {
  708. #endif
  709.             mlwrite("File read error");
  710.             return (FIOERR);
  711.             }
  712.         if (i != 0)
  713.             {
  714.             mlwrite("Added newline at EOF");
  715.             return (FIOFNF);    /* dal: indicate nl missing */
  716.             }
  717.         return (FIOEOF);
  718.         }
  719.     return (FIOSUC);
  720.     }
  721.  
  722. /*
  723.  * file: spawn.c
  724.  *
  725.  * The routines in this file
  726.  * are called to create a subjob running
  727.  * a command interpreter. This code is a big
  728.  * fat nothing on CP/M-86. You lose.
  729.  * dal: added single program execution for AtST
  730.  * dal: added built in command shell for AtST
  731.  * dal: removed internal shell and added support for system() call
  732.  *    in dLibs, which handles _shell_p, etc.
  733.  */
  734.  
  735. #if    VMS
  736. #define    EFN    0                /* Event flag.        */
  737.  
  738. #include    <ssdef.h>            /* Random headers.    */
  739. #include    <stsdef.h>
  740. #include    <descrip.h>
  741. #include    <iodef.h>
  742.  
  743. extern    int    oldmode[];            /* In "termio.c"    */
  744. extern    int    newmode[];            /* In "termio.c"    */
  745. extern    short    iochan;                /* In "termio.c"    */
  746. #endif
  747.  
  748. #if    MSDOS
  749. #include    <dos.h>
  750. #endif
  751.  
  752. #if    V7
  753. #include    <signal.h>
  754. #endif
  755.  
  756. /*
  757.  * Create a subjob with a copy
  758.  * of the command intrepreter in it. When the
  759.  * command interpreter exits, mark the screen as
  760.  * garbage so that you do a full repaint. Bound
  761.  * to "C-C". The message at
  762.  * the start in VMS puts out a newline. Under
  763.  * some (unknown) condition, you don't get one
  764.  * free when DCL starts up.
  765.  */
  766. spawncli(f, n)
  767.     {
  768. #if    V7
  769.     register char *cp;
  770.     char    *getenv();
  771. #endif
  772. #if    VMS
  773.     movecursor(term.t_nrow, 0);        /* In last line.    */
  774.     mlputs("[Starting DCL]\r\n");
  775.     (*term.t_flush)();            /* Ignore "ttcol".    */
  776.     sgarbf = TRUE;
  777.     return (sys(NULL));            /* NULL => DCL.        */
  778. #endif
  779. #if    AtST
  780.     mouse_dead();                /* no mouse cursor motion */
  781.     movecursor(term.t_nrow, 0);
  782.     (*term.t_putchar)('\r');
  783.     (*term.t_putchar)('\n');
  784.     (*term.t_flush)();
  785.     shell();
  786.     sgarbf = TRUE;
  787.     mouse_live();                /* reactivate mouse cursor */
  788.     return(TRUE);
  789. #endif
  790. #if    CPM
  791.     mlwrite("Can't spawn a shell in CP/M-86");
  792.     return (FALSE);
  793. #endif
  794. #if    MSDOS
  795.     movecursor(term.t_nrow, 0);        /* Seek to last line.    */
  796.     (*term.t_flush)();
  797.     sys("\\command.com", "");        /* Run CLI.        */
  798.     sgarbf = TRUE;
  799.     return(TRUE);
  800. #endif
  801. #if    V7
  802.     movecursor(term.t_nrow, 0);        /* Seek to last line.    */
  803.     (*term.t_flush)();
  804.     ttclose();                /* stty to old settings    */
  805.     if ((cp = getenv("SHELL")) != NULL && *cp != '\0')
  806.         system(cp);
  807.     else
  808.         system("exec /bin/sh");
  809.     sgarbf = TRUE;
  810.     sleep(2);
  811.     ttopen();
  812.     return(TRUE);
  813. #endif
  814.     }
  815.  
  816. /*
  817.  * Run a one-liner in a subjob.
  818.  * When the command returns, wait for a single
  819.  * character to be typed, then mark the screen as
  820.  * garbage so a full repaint is done.
  821.  * Bound to "C-X !".
  822.  */
  823. spawn1(f, n)
  824.     {
  825.     register int    s;
  826.     char        line[NLINE];
  827.  
  828. #if    VMS
  829.     if ((s=mlreply("DCL command: ", line, NLINE)) != TRUE)
  830.         return (s);
  831.     (*term.t_putchar)('\n');        /* Already have '\r'    */
  832.     (*term.t_flush)();
  833.     s = sys(line);                /* Run the command.    */
  834.     mlputs("\r\n\n[End]");            /* Pause.        */
  835.     (*term.t_flush)();
  836.     while ((*term.t_getchar)() != '\r')
  837.         ;
  838.     sgarbf = TRUE;
  839.     return (s);
  840. #endif
  841. #if    AtST
  842.     if ((s=mlgets("Shell command", NULL, line, NLINE, CRLF)) == ABORT)
  843.         return (s);
  844.     if (*line) 
  845.         {
  846.         (*term.t_putchar)('\n');    /* Already have '\r' */
  847.         (*term.t_flush)();
  848.         mouse_dead();            /* no mouse cursor motion */
  849.         s = system(line);
  850.         mlwrite( "Hit [RETURN] to re-enter MicroEMACS..." );
  851.         while ((*term.t_getchar)() != '\r')
  852.             ;
  853.         mouse_live();            /* reactivate mouse cursor */
  854.         sgarbf = TRUE;
  855.         if(s != 0) 
  856.             {
  857.             mlpending( "Exit code %d", s);
  858.             return(FALSE);
  859.             }
  860.         return(TRUE);
  861.         }
  862.     return(FALSE);
  863. #endif
  864. #if    CPM
  865.     mlwrite("No command exec for CP/M-86");
  866.     return (FALSE);
  867. #endif
  868. #if    MSDOS
  869.     if ((s=mlreply("MS-DOS command: ", line, NLINE)) != TRUE)
  870.         return (s);
  871.     system(line);
  872.     mlwrite( "Hit [RETURN] to re-enter MicroEMACS..." );
  873.     while ((*term.t_getchar)() != '\r')    /* Pause.        */
  874.         ;
  875.     sgarbf = TRUE;
  876.     return (TRUE);
  877. #endif
  878. #if    V7
  879.     if ((s=mlreply("! ", line, NLINE)) != TRUE)
  880.         return (s);
  881.     (*term.t_putchar)('\n');        /* Already have '\r'    */
  882.     (*term.t_flush)();
  883.     ttclose();                /* stty to old modes    */
  884.     system(line);
  885.     sleep(2);
  886.     ttopen();
  887.     mlputs("[End]");            /* Pause.        */
  888.     (*term.t_flush)();
  889.     while ((s = (*term.t_getchar)()) != '\r' && s != ' ')
  890.         ;
  891.     sgarbf = TRUE;
  892.     return (TRUE);
  893. #endif
  894.     }
  895.  
  896. #if    VMS
  897. /*
  898.  * Run a command. The "cmd" is a pointer
  899.  * to a command string, or NULL if you want to run
  900.  * a copy of DCL in the subjob (this is how the standard
  901.  * routine LIB$SPAWN works. You have to do wierd stuff
  902.  * with the terminal on the way in and the way out,
  903.  * because DCL does not want the channel to be
  904.  * in raw mode.
  905.  */
  906. sys(cmd)
  907. register char    *cmd;
  908.     {
  909.     struct    dsc$descriptor    cdsc;
  910.     struct    dsc$descriptor    *cdscp;
  911.     long    status;
  912.     long    substatus;
  913.     long    iosb[2];
  914.  
  915.     status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  916.               oldmode, sizeof(oldmode), 0, 0, 0, 0);
  917.     if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  918.         return (FALSE);
  919.     cdscp = NULL;                /* Assume DCL.        */
  920.     if (cmd != NULL)             /* Build descriptor.    */
  921.         {
  922.         cdsc.dsc$a_pointer = cmd;
  923.         cdsc.dsc$w_length  = strlen(cmd);
  924.         cdsc.dsc$b_dtype   = DSC$K_DTYPE_T;
  925.         cdsc.dsc$b_class   = DSC$K_CLASS_S;
  926.         cdscp = &cdsc;
  927.         }
  928.     status = LIB$SPAWN(cdscp, 0, 0, 0, 0, 0, &substatus, 0, 0, 0);
  929.     if (status != SS$_NORMAL)
  930.         substatus = status;
  931.     status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
  932.               newmode, sizeof(newmode), 0, 0, 0, 0);
  933.     if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
  934.         return (FALSE);
  935.     if ((substatus&STS$M_SUCCESS) == 0)    /* Command failed.    */
  936.         return (FALSE);
  937.     return (TRUE);
  938.     }
  939. #endif
  940.  
  941. #if    MSDOS
  942. /*
  943.  * This routine, once again
  944.  * by Bob McNamara, is a C translation
  945.  * of the "system" routine in the MWC-86 run
  946.  * time library. It differs from the "system" routine
  947.  * in that it does not unconditionally append the
  948.  * string ".exe" to the end of the command name.
  949.  * We needed to do this because we want to be
  950.  * able to spawn off "command.com". We really do
  951.  * not understand what it does, but if you don't
  952.  * do it exactly "malloc" starts doing very
  953.  * very strange things.
  954.  */
  955. sys(cmd, tail)
  956.     char    *cmd;
  957.     char    *tail;
  958.     {
  959.     register unsigned n;
  960.     extern   char      *__end;
  961.  
  962.     n = __end + 15;
  963.     n >>= 4;
  964.     n = ((n + dsreg() + 16) & 0xFFF0) + 16;
  965.     return(execall(cmd, tail, n));
  966.     }
  967. #endif
  968.  
  969. #if    AtST
  970. static    char    *_fn_lst = NULL;
  971.  
  972. /*
  973.  * dal: This routine builds the directory text
  974.  * in the special secret buffer. It is called
  975.  * by mlgetfn() via make_popup(). Returns TRUE
  976.  * if everything works. Returns FALSE if there
  977.  * is an error (if there is no memory).
  978.  */
  979. make_dir(buffer, data)
  980.     BUFFER    *buffer;
  981.     char    *data;        /* dal: cheat a bit here... */
  982.     {
  983.     register char *p, *q;
  984.     register int i, n;
  985.     register long tsize;
  986.     char line[128];
  987.     struct stat dir, *oldirp;
  988.  
  989.     bbclear(buffer);        /* Blow old text away */
  990.     n = 0;
  991.     sprintf(line, "\tDirectory of %s", data);
  992.     if(_fn_lst)
  993.         free(_fn_lst);
  994.     _fn_lst = strdup(data);
  995.     if(_fn_lst && (p = strrpbrk(_fn_lst, "\\:"))) 
  996.         {
  997.         *p++ = '\0';
  998.         *p = '\0';
  999.         }
  1000.     if (addline(line, buffer) == FALSE)
  1001.         return(FALSE);
  1002.     oldirp = Fgetdta();
  1003.     Fsetdta(&dir);
  1004.     if(Fsfirst(data, 0x10) == 0)        /* include sub-directories */
  1005.         do 
  1006.             {
  1007.             if(dir.st_mode == S_IFDIR)     /* directory entry */
  1008.                 {
  1009.                 p = dir.st_name;
  1010.                 if(!strcmp(p, ".") || !strcmp(p, ".."))
  1011.                     continue;
  1012.                 sprintf(line, "\t<DIR>  %s\\", p);
  1013.                 }
  1014.             else 
  1015.                 {
  1016.                 ++n;
  1017.                 tsize += dir.st_size;
  1018.                 sprintf(line, "\t%6ld %s",
  1019.                     dir.st_size, dir.st_name);
  1020.                 if(_fn_lst) 
  1021.                     {
  1022.                     i = ((int) msize(_fn_lst));
  1023.                     _fn_lst = realloc(_fn_lst, i+16);
  1024.                     if(_fn_lst) 
  1025.                         {
  1026.                         p = strrchr(_fn_lst, '\0');
  1027.                         *p++ = '|';
  1028.                         strcpy(p, dir.st_name);
  1029.                         }
  1030.                     }
  1031.                 }
  1032.             if (addline(line, buffer) == FALSE) 
  1033.                 {
  1034.                 Fsetdta(oldirp);
  1035.                 return(FALSE);
  1036.                 }
  1037.             }
  1038.             while(Fsnext() == 0);
  1039.     Fsetdta(oldirp);
  1040.     sprintf(line, "\t%5d files (%ld bytes).", n, tsize);
  1041.     if (addline(line, buffer) == FALSE)
  1042.         return(FALSE);
  1043.     return (TRUE);         /* All done */
  1044.     }
  1045. #endif AtST
  1046.  
  1047. /*
  1048.  * dal: Get a file name from the user.
  1049.  * If the string contains wildcard characters,
  1050.  * give a directory of files matching the
  1051.  * file spec and re-prompt until a valid
  1052.  * non-ambiguous file name is obtained.
  1053.  */
  1054. mlgetfn(prompt, buf, len)
  1055.     char *prompt, *buf;
  1056.     int len;
  1057.     {
  1058.     register int s, popped = FALSE;
  1059.     char tmp[128], *p = NULL, *q = NULL, *r;
  1060.  
  1061. #if AtST
  1062.     p = NULL;
  1063.     for(;;) 
  1064.         {
  1065.         if((s=mlgets(prompt, p, buf, len, "\r\n+-")) == ABORT) 
  1066.             {
  1067.             if(popped)
  1068.                 onlywind(FALSE,1);
  1069.             return(s);
  1070.             }
  1071.         if((buf[0] == '\0') && p)    /* default */
  1072.             strcpy(buf, p);
  1073.         if(popped && q) 
  1074.             {
  1075.             if(s == '+') 
  1076.                 {
  1077.                 if((q = strchr(q, '|')) == NULL)
  1078.                     q = strchr(_fn_lst, '\0');
  1079.                 goto MAKE_FN;
  1080.                 }
  1081.             if(s == '-') 
  1082.                 {
  1083.                 if(*--q == '\0') {
  1084.                     p = strrchr(q+1, '|');
  1085.                     if(p)
  1086.                         q = p;
  1087.                 }
  1088.                 else
  1089.                     while((*--q) && (*q != '|'))
  1090.                         ;
  1091.                 goto MAKE_FN;
  1092.                 }
  1093.             }
  1094.         else if((s == '+') || (s == '-'))
  1095.             continue;
  1096.         if(!(strchr(buf, '*') || strchr(buf, '?')))  /* no wildcards */
  1097.             return(popped ? onlywind(FALSE,1) : TRUE);
  1098.         fullpath(buf, buf);
  1099.         if ((s=make_popup(bdirp, make_dir, buf)) != TRUE)
  1100.             return(s);
  1101.         if(q = strchr(_fn_lst, '|'))
  1102.             *q = '\0';
  1103.         if(q == NULL)
  1104.             q = strchr(_fn_lst, '\0');
  1105.         popped = TRUE;
  1106. MAKE_FN:    p = strcpy(tmp, _fn_lst);
  1107.         r = strrchr(p, '\0');
  1108.         *r++ = '\\';
  1109.         memccpy(r, ++q, '|', 16);
  1110.         if(r = strchr(r, '|'))
  1111.             *r = '\0';
  1112.         update();
  1113.         }
  1114. #else
  1115.     return(mlgets(prompt, NULL, buf, len, CRLF) != ABORT);
  1116. #endif
  1117.     }
  1118.